
/*******************************************************************************
 * Copyleft (c) 2021 Kcode
 *
 * @file    dma.c
 * @brief   jz2440开发板的相关硬件操作与初始化
 * @author  K
 * @version 0.0.1
 * @date    2021-08-05
 * @license MulanPSL-1.0
 *
 * 文件修改历史：
 * <时间>       | <版本>    | <作者>  | <描述>
 * 2021-08-06   | v0.0.1    | Kcode   | jz2440开发板的相关硬件操作与初始化
 * -----------------------------------------------------------------------------
 ******************************************************************************/

#include "stdio.h"

/*!
 * S3C2440中的每个DMA
 */
#define DMA0_BASE_ADDR  0x4B000000
#define DMA1_BASE_ADDR  0x4B000040
#define DMA2_BASE_ADDR  0x4B000080
#define DMA3_BASE_ADDR  0x4B0000C0

/*!
 * DMA操作的相关寄存器
 */
typedef struct s3c_dma_regs {
	unsigned long disrc;
	unsigned long disrcc;
	unsigned long didst;
	unsigned long didstc;
	unsigned long dcon;
	unsigned long dstat;
	unsigned long dcsrc;
	unsigned long dcdst;
	unsigned long dmasktrig;
}S3C_DMA_REG_S;

S3C_DMA_REG_S *s_dma_regs;

static int s_dma_src_rep;   /**< 记录dma传输的源数据地址 */
static int s_dma_len_rep;   /**< 记录dma传输的源数据长度 */

/*!
 * @brief  初始化dma传输时的相关寄存器，数据最终自动存储在IISFIFO寄存器
 * @param[in] src 数据的源地址
 * @param[in] len 数据的长度
 * @return void
 */
void dma_init(unsigned int src, unsigned int len)
{
    if (src == 0 || len == 0)
    {
        printf("Please check src :%d len : %d\n", src, len);
        return ;
    }
    
    s_dma_src_rep = src;
    s_dma_len_rep = len;

    s_dma_regs = (S3C_DMA_REG_S *)DMA2_BASE_ADDR;
    
    /* 把源,目的,长度告诉DMA */
    s_dma_regs->disrc = src;   /* 源的物理地址 */

    /* 源位于AHB总线, 源地址递增 */
    s_dma_regs->disrcc = (0 << 1) | (0 << 0); 

    /* 目的的物理地址 */
    s_dma_regs->didst = 0x55000010;       

    /* 目的位于APB总线, 目的地址不变 */
    s_dma_regs->didstc = (0 << 2) | (1 << 1) | (1 << 0); 

    /* 使能中断,单个传输,硬件触发 */
    s_dma_regs->dcon = (1 << 31) | (0 << 30) | (1 << 29) | (0 << 28) |\
                      (0 << 27) | (0 << 24) | (1 << 23) | (1 << 20) | (len / 2);
}

/*!
 * @brief  启动DMA
 * @return void
 */
void dma_start(void)
{
	s_dma_regs->dmasktrig  = (1 << 1);
}

/*!
 * @brief  停止DMA传输
 * @return void
 */
void dma_stop(void)
{
	s_dma_regs->dmasktrig  &= ~(1 << 1);
}

/*!
 * @brief  dma重新传输数据(视频重播)
 * @return void
 */
void dma_repeat(void)
{
    dma_init(s_dma_src_rep, s_dma_len_rep);
}

/*!
 * @brief  DMA中断处理函数
 * @return void
 */
void dma2_init_handle(void)
{
    printf("dma2 done\n\r");
    dma_repeat();
}
